package com.macro.mall.demo.service.impl;


import com.macro.mall.common.es.EsIndexDto;
import com.macro.mall.demo.service.EsIndexService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;
import org.elasticsearch.client.indices.PutMappingRequest;
import org.elasticsearch.common.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Map;

/**
 * @Author：hwh
 * @Description:
 * @name：EsServiceImpl
 * @Date：2024/10/15 20:39
 */
@Service
@Slf4j
public class EsIndexServiceImpl implements EsIndexService {

    @Autowired
    private RestHighLevelClient client;

    @Override
    public void createIndex(EsIndexDto esIndexDto) {
        // 查询索引是否存在
        boolean indexExists = indexExists(esIndexDto.getIndexName());

        if (indexExists) {
            log.warn("索引创建失败，索引名称已存在: {}", esIndexDto.getIndexName());
            throw new RuntimeException("索引名称已存在,请勿重复创建!!");
        }

        log.info("开始创建索引，索引名称: {}, 映射: {}", esIndexDto.getIndexName(), esIndexDto.getIndexMappings());

        try {
            CreateIndexRequest createIndexRequest = new CreateIndexRequest(esIndexDto.getIndexName());
            // 将 JSON 映射添加到请求中
            if (StringUtils.isNotBlank(esIndexDto.getIndexMappings())) {
                createIndexRequest.mapping(esIndexDto.getIndexMappings(), XContentType.JSON);
                log.debug("添加映射信息到创建请求，映射: {}", esIndexDto.getIndexMappings());
            }

            // 发送请求
            client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
            log.info("索引创建成功，索引名称: {}", esIndexDto.getIndexName());
        } catch (Exception e) {
            log.error("创建索引失败, 索引名称: {}, 异常信息: {}", esIndexDto.getIndexName(), e.getMessage(), e);
            throw new RuntimeException("创建索引失败", e);
        }
    }


    /**
     * 查询索引
     */
    @Override
    public boolean indexExists(String indexName) {
        log.info("开始查询索引，索引名称: {}", indexName);

        // 创建查询索引构造
        GetIndexRequest getIndexRequest = new GetIndexRequest(indexName);
        try {
            // 发送请求并返回索引是否存在
            boolean exists = client.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
            log.info("查询索引成功，索引名称: {}, 存在: {}", indexName, exists);
            return exists;
        } catch (IOException e) {
            log.error("查询索引异常，索引名称: {}, 异常信息: {}", indexName, e.getMessage(), e);
            throw new RuntimeException("查询索引失败", e);
        }
    }


    /**
     * 修改索引
     *
     * @param esIndexDto
     */
    @Override
    public void updIndex(EsIndexDto esIndexDto) {
        log.info("开始修改索引，索引名称: {}", esIndexDto.getIndexName());

        // 查询索引是否存在
        boolean indexExists = indexExists(esIndexDto.getIndexName());

        if (!indexExists) {
            log.error("索引不存在，无法修改，索引名称: {}", esIndexDto.getIndexName());
            throw new RuntimeException("索引不存在，请创建");
        }

        // 创建修改索引构造
        PutMappingRequest putMappingRequest = new PutMappingRequest(esIndexDto.getIndexName());

        // 判断是否修改映射
        if (StringUtils.isNotBlank(esIndexDto.getIndexMappings())) {
            putMappingRequest.source(esIndexDto.getIndexMappings(), XContentType.JSON);
            log.info("准备更新索引映射，索引名称: {}, 新映射: {}", esIndexDto.getIndexName(), esIndexDto.getIndexMappings());
        } else {
            log.warn("未提供新的索引映射，索引名称: {}", esIndexDto.getIndexName());
        }

        try {
            client.indices().putMapping(putMappingRequest, RequestOptions.DEFAULT);
            log.info("成功修改索引，索引名称: {}", esIndexDto.getIndexName());
        } catch (IOException e) {
            log.error("修改索引时发生异常，索引名称: {}, 异常信息: {}", esIndexDto.getIndexName(), e.getMessage(), e);
            throw new RuntimeException("修改索引失败", e);
        }
    }

    /**
     * 获取索引信息
     *
     * @param indexName
     * @return
     */
    @Override
    public Map<String, Object> getInfo(String indexName) {
        log.info("开始获取索引信息，索引名称: {}", indexName);

        // 查询索引是否存在
        boolean indexExists = indexExists(indexName);

        // 如果索引不存在，抛出运行时异常
        if (!indexExists) {
            log.error("索引不存在，无法获取信息，索引名称: {}", indexName);
            throw new RuntimeException("索引不存在，请创建索引：" + indexName);
        }

        // 创建用于获取索引信息的请求对象
        GetIndexRequest getIndexRequest = new GetIndexRequest(indexName);

        try {
            // 执行获取索引信息的请求
            GetIndexResponse getIndexResponse = client.indices().get(getIndexRequest, RequestOptions.DEFAULT);

            // 获取索引的映射信息并返回
            Map<String, Object> indexMappings = getIndexResponse.getMappings().get(indexName).sourceAsMap();
            log.info("成功获取索引信息，索引名称: {}", indexName);
            return indexMappings;
        } catch (IOException e) {
            // 日志记录错误信息并抛出运行时异常
            log.error("获取索引信息失败，索引名称: {}, 异常信息: {}", indexName, e.getMessage(), e);
            throw new RuntimeException("获取索引信息失败，索引名称：" + indexName, e);
        }
    }


    /**
     * 删除索引
     *
     * @param indexName
     */
    @Override
    public void delIndex(String indexName) {
        log.info("开始删除索引，索引名称: {}", indexName);

        // 查询索引是否存在
        boolean indexExists = indexExists(indexName);

        // 如果索引不存在，抛出运行时异常
        if (!indexExists) {
            log.error("索引不存在，无法删除，索引名称: {}", indexName);
            throw new RuntimeException("索引不存在，请创建索引：" + indexName);
        }

        // 创建删除索引请求
        DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName);

        try {
            // 执行删除索引的请求
            client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);
            log.info("成功删除索引: {}", indexName);  // 记录成功删除的日志
        } catch (IOException e) {
            // 记录错误信息并抛出运行时异常，保持上下文
            log.error("删除索引失败，索引名称: {}, 异常信息: {}", indexName, e.getMessage(), e);
            throw new RuntimeException("删除索引失败，索引名称：" + indexName, e);
        }
    }

}
